// 服务器端渲染
const fs = require('fs')
const path = require('path')
const os = require('os')

const resolve = file => path.resolve(__dirname, file)
const config = require(resolve('../config/env'))
const storeHtml = require('./storeHtml')

module.exports = app => {
  function createRenderer(bundle, template) {
    // https://github.com/vuejs/vue/blob/dev/packages/vue-server-renderer/README.md#why-use-bundlerenderer
    return require('vue-server-renderer').createBundleRenderer(bundle, {
      template,
      // 缓存
      cache: require('lru-cache')({
        max: 1000,
        maxAge: 1000 * 60 * 15
      }),
      runInNewContext: false
    })
  }

  let renderer

  if (!config.environment.includes('isLocal')) {
    // 生产创建服务端渲染使用 server bundle 和 html
    // server bundle的生成依赖于 vue-ssr-webpack-plugin 插件
    const bundle = require(resolve('../vue-ssr-bundle.json'))

    // html模板由 html-webpack-plugin 插件注入资源并输出 'dist/index.html'
    const template = fs.readFileSync(resolve('../index.html'), 'utf-8')
    renderer = createRenderer(bundle, template)
  } else {
    // 开发模式需要设置 dev-server 和 hot-reload
    // 创建一个新renderer更新模板
    const setupDevServer = require('../build/setup-dev-server')
    setupDevServer(app, (bundle, template) => {
      renderer = createRenderer(bundle, template)
    })
  }
  app.get('*', (req, res) => {
    // 未渲染好返回
    if (!renderer) {
      return res.end('waiting for compilation... refresh in a moment.')
    }
    res.setHeader('Content-Type', 'text/html')
    let isMobile = false
    let isSpider = false
    let userAgent = req.headers['user-agent'] || ''
    if (userAgent && /mobile/i.test(userAgent)) {
      isMobile = true
    }

    // 根据请求userAgent判断当前是否为爬虫
    let spiderUserAgentList = ['www.baidu.com', 'www.so.com', 'www.sogou.com', 'www.bing.com', '360Spider']
    let spiderRedirectDoaminList = [
      'cp.zlketang.com',
      'shenji.zlketang.com',
      'cpm.zlketang.com',
      'shenjim.zlketang.com'
    ]

    // 是否包含搜索引擎名单,并且处于cs环境
    let currentHost = req.headers.host || ''
    // 从搜索页面跳转过来
    let referer = req.headers.referer || ''
    let isSpiderDoamin = spiderUserAgentList.some(item => userAgent.includes(item))
    let isSpiderRedirectDoamin = spiderRedirectDoaminList.some(
      item => (currentHost && currentHost.includes(item)) || (referer && referer.includes(item))
    )
    if (isSpiderDoamin && isSpiderRedirectDoamin) {
      isSpider = true
    }

    isSpider = false

    let urlPath = req.url || '/'
    const errorHandler = err => {
      // js-ignore
      console.log(
        'Time:' + parseInt(Date.now() / 1000),
        'renderer errorHandler url:' + req.url,
        err
      )
      if (err && err.code === 404) {
        //判断不支持的文件类型
        urlPath = urlPath.split('?')[0]
        let isUnsupportedEndWith = /\.(php|jsp|rar|zip|asp|aspx|gz|tar|sql|git|txt|svn)\/?$/.test(urlPath)
        let isResource = /\.(js|css|html|png|jpeg|jpg|png|gif|pdf|doc|docx|ppt)$/.test(urlPath)
        let resourceDesc = isResource || isUnsupportedEndWith ? '资源丢失了' : '页面丢失了'
        let notFoundHtml = `<!DOCTYPE html>
          <html lang="en">
            <head>
              <meta charset="UTF-8" />
              <meta name="viewport" content="width=device-width, initial-scale=1.0" />
              <title>404页面-之了课堂</title>
              <style>
                * {
                  box-sizing: border-box;
                  padding: 0;
                  margin: 0;
                }
                .page-content {
                  height: 100vh;
                }
                .el-button {
                  -webkit-appearance: none;
                  background: #fff;
                  border: 1px solid #dcdfe6;
                  border-radius: 4px;
                  -webkit-box-sizing: border-box;
                  box-sizing: border-box;
                  color: #606266;
                  cursor: pointer;
                  display: inline-block;
                  font-size: 14px;
                  font-weight: 500;
                  line-height: 1;
                  margin: 0;
                  outline: 0;
                  padding: 12px 20px;
                  text-align: center;
                  -webkit-transition: 0.1s;
                  transition: 0.1s;
                  white-space: nowrap;
                  -webkit-user-select: none;
                  -moz-user-select: none;
                  -ms-user-select: none;
                }
                button {
                  background-color: transparent;
                  border: none;
                  outline: 0;
                }
                .not-found-btn {
                  background: #3480ff;
                  border-radius: 4px;
                  color: #fff;
                  font-size: 16px;
                  font-weight: 700;
                  height: 40px;
                  margin-top: 30px;
                  width: 330px;
                }
          
                .page-content {
                  flex-direction: column;
                  display: flex;
                  align-items: center;
                  justify-content: center;
                }
                .not-found-title {
                  margin-top: -9px;
                  font-size: 16px;
                  font-weight: 400;
                  color: #667080;
                  line-height: 22px;
                }
              </style>
            </head>
            <body>
              <div class="page-content flex-center">
                <img
                  src="//image.zlketang.com/public/news/images/new_official/other/404.png"
                  alt="404"
                />
                <div class="not-found-title">十分抱歉，${resourceDesc}</div>
                <button class="el-button not-found-btn" onclick="goBack()">返回上一页</button>
              </div>
              <script>
                function goBack() {
                  history.go(-1)
                }
              </script>
            </body>
          </html>`
        res.status(404).end(notFoundHtml)
      } else {
        // Render Error Page or Redirect
        res.status(500).end('500 | Internal Server Error')
      }
    }

    let title = '之了课堂' // 自定义变量（此处用于title）
    let keywords = '之了课堂'
    let description =
      '之了课堂，是成都环宇知了科技有限公司开发的在线学习平台。之了课堂专注于会计培训，是一个综合型、创新型会计类在线教育平台及学习方案提供者，开设各类财会考试培训和实操指导，为会计人提供有效的学习方案'
    if (req.seoConfig) {
      title = req.seoConfig.title
      keywords = req.seoConfig.keywords
      description = req.seoConfig.description
    }
    // 非正式环境域名
    // js-ignore
    const otherList = [
      'cp.zlketang.com',
      'shenji.zlketang.com',
      'm.zlketang.com',
      'www.zlketang.net',
    ]
    // 除了正式别的域名使用“测试站”
    if (otherList.includes(req.host)) {
      title = '测试站'
      keywords = '测试站'
      description = ''
    }
    let arr = []
    let globalConfig = {
      // PC端域名
      pcDomain: '',
      // PC端跟随协议域名
      pcFollowDomain: '',
      // 协议
      protocol:''
    }
    let port = req.headers['x-forwarded-port']
    let protocol = req.headers['x-forwarded-proto'] || req.protocol

    let originalUrl = `${protocol}://${req.headers.host}`
    // 注册全局配置域名  和跟随协议域名
    globalConfig.pcDomain = `${protocol}://${req.headers.host}`
    globalConfig.pcFollowDomain = `//${req.headers.host}`
    globalConfig.protocol = protocol
    if (port && ![80, 443].includes(+port)) {
      originalUrl = originalUrl + ':' + port
      globalConfig.pcDomain =  globalConfig.pcDomain + ':' + port
      globalConfig.pcFollowDomain =  globalConfig.pcFollowDomain + ':' + port
    }
    let context = {
      title,
      keywords,
      description,
      url: req.url,
      asyncDataCache: false,
      extendJS: '',
      extendCSS: '',
      skinType: '',
      isMobile,
      originalUrl,
      globalConfig, //注册全局配置域名
      isSpider
    }
    // 服务端渲染
    renderer
      .renderToStream(context) // 可传参数来渲染模板页 url: req.url 必传 其为entry-server.js入参 context
      .on('error', errorHandler)
      .on('data', function(chunk) {
        arr.push(chunk) //读取文件时，是buffer类型，将每次读取的buffer拼到一个数组内
      })
      .on('end', () => {
        let htmlContent = Buffer.concat(arr).toString()
        //请求响应时间
        let responseTime = Date.now() - req.xRequest.time // ms单位
        res.setHeader('X-Request-Id', req.xRequest.id + '-' + responseTime + '-1')
        if (req.seoConfig && req.seoConfig.isUserCacheSeo) {
          res.setHeader('X-Request-SEO', '' + req.seoConfig.isUserCacheSeo)
        }
        res.setHeader('Cache-Control', 'public,max-age=' + config.cacheHtmlTime)

        //重要信息：缓存页面只支持req.path不带参数缓存，或者页面渲染与参数无关可以配置缓存
        //判断依据：配置vue页面asyncDataCache为true
        //当asyncData不存在，则可以支持asyncDataCache为true
        //当asyncData存在，页面渲染依赖于router.query，则不能配置缓存；如果依赖于router.params，可以配置缓存
        let cacheKey = storeHtml.getCacheKey(req.path)
        if (!context.asyncDataCache || !cacheKey || !htmlContent) {
          return res.end(htmlContent || '')
        }

        storeHtml.setItem(cacheKey, htmlContent)
        //Cannot set headers after they are sent to the client
        res.send(htmlContent)
      })
  })
}
